# -*- coding: utf-8 -*-
"""
Created on Wed Aug 21 15:04:30 2013

@author: jkwong
"""
#PBAR_Cargo.py

import csv
import numpy as np
import numpy.matlib
import datetime
import time
import os
import codecs
from xml.dom.minidom import parseString

def ReadCargoImage(filename):
    fid = open(filename, 'rb')
    ignore = np.fromfile(fid, np.uint32, 4)
    bpp = np.fromfile(fid, np.uint32,1)
    height = np.fromfile(fid, np.uint32,1)
    width = np.fromfile(fid, np.uint32,1)
    formatt = np.fromfile(fid, np.uint32,1)
    flag = np.fromfile(fid, np.uint32,1)
    ignore = np.fromfile(fid, np.uint32,2)
    
    low1,high1,low2,high2 = (0, 0, 0, 0) 

    if formatt == 1: # 16bit Single Energy Data
        A = np.fromfile(fid,np.uint16, height*width).reshape(width,height);
    elif formatt == 2: # 32bit Single Energy Data
        A = np.fromfile(fid, np.uint32, height*width).reshape(width,height);
    elif formatt == 3: # 16bit Dual Energy Data
        i = np.linspace(1,height,height);
        A = np.fromfile(fid,np.uint16, height*2*width)
        low1 = A[2*i-1,:]; # Low Energy Data
        high1 = A[2*i,:];  # High Energy Data
    elif formatt == 4: # 8bit Single Energy Data
        A = np.fromfile(fid,np.uint8, height*width);
    elif formatt == 5: # 32bit Dual Energy Data
        i = np.linspace(1,height,height);
        A = np.fromfile(fid,np.uint32, height*2*width);
        low1 = A[2*i-1,:]; # Low Energy Data
        high1 = A[2*i,:];  # High Energy Data
    elif formatt == 6: # 32bit Quad Energy Data
        i = np.linspace(1,height,height);
        A = np.fromfile(fid,np.uint32, height*4*width);
        low1 = A[4*i-3,:];  # First set of Low Energy Data
        high1 = A[4*i-2,:]; # First set of High Energy Data
        low2 = A[4*i-1,:];  # % Second set of Low Energy Data
        high2 = A[4*i,:];   # Second set of High Energy Data
    else:
        print('Unrecognized data format')
    
    fid.close()
    return(A,bpp,formatt,flag,low1,high1,low2,high2)
    
def ReadCargoMarker(filename):
    """ Reading in cargomarker file using xml.dom.minidom.parseString"""
    markers = []
    with codecs.open(filename, 'rb', encoding = 'utf-16') as fid:
        txt = fid.read()
        fid.close()
        txt = '<root>' + txt + '</root>'
        txt = txt.replace('\n', '').replace('\r', '')
        dom = parseString(txt)
        # loop over childNodes
        for (nodeIndex, node) in enumerate(dom.childNodes[0].childNodes):
            temp = {}
            temp['shape'] = node.getAttribute('type')
            temp['color'] = node.childNodes[0].getAttribute('value')
            temp['locked'] = node.childNodes[1].getAttribute('value')
            # rect
            temp['rec_bottom'] = float(node.childNodes[2].getAttribute('bottom'))
            temp['rec_left'] = float(node.childNodes[2].getAttribute('left'))
            temp['rec_right'] = float(node.childNodes[2].getAttribute('right'))
            temp['rec_top'] = float(node.childNodes[2].getAttribute('top'))
            temp['target'] = node.childNodes[3].getAttribute('value')
            temp['done'] = node.childNodes[4].getAttribute('done')
            temp['suspicious'] = node.childNodes[4].getAttribute('suspicious')
            temp['x'] = float(node.childNodes[4].getAttribute('x'))
            temp['y'] = float(node.childNodes[4].getAttribute('y'))
            # left
            temp2 = {}
            if len(node.childNodes) > 5:
                temp2['x'] = float(node.childNodes[5].getAttribute('x'))
                temp2['y'] = float(node.childNodes[5].getAttribute('y'))
                temp[node.childNodes[5].nodeName] = temp2
            # right
            temp2 = {}
            if len(node.childNodes) > 6:
                temp2['x'] = float(node.childNodes[6].getAttribute('x'))
                temp2['y'] = float(node.childNodes[6].getAttribute('y'))
                temp[node.childNodes[6].nodeName] = temp2
            
            markers.append(temp)
#    return(markers, dom, txt)
    return(markers)

def ReadLabelFile(filename, r_flag):
    # default values
    col = 3072;
    row = 544;
    if os.path.exists(filename):
        if r_flag == 'u':  # not sure about
            fid = codecs.open(filename, 'rb', encoding = 'utf-16')
        else:
            fid = codecs.open(filename, 'rb', encoding = 'utf-8')
        lineIn = fid.read()
        col,row = lineIn.replace(' ', '').replace('COLUMNS:', '').replace('ROWS:', ',').split(',')            
        fid.close()
    else:
        print('File: %s does not exist. Using Default size: (%d x %d)' %(filename, col, row));
    return(int(row),int(col))
    
def ReadCargoImageDR(filename):
    with open(filename, 'rb') as fid:
        row, col = ReadLabelFile(filename.replace('DR', 'DR$LA'), 'm')
        img = np.fromfile(fid, np.int16, row*col).reshape(row,col);
    img = np.flipud(img).T
    return(img)        
# fid=fopen(char(filenames(fi)),'r');
#    img=fread(fid,'short');
#    imga=img(1:col_size*row_size);
#    fclose(fid);
#    rimgtmp=zeros(col_size,row_size);%rimgtmp=zeros(3072,544);
#    rimga=reshape(imga,[col_size,row_size]);%

def FindCargoStart(filename, lowerBound = 10, upperBound = 300, yLower = 100, yUpper = 200, yLowerAboveCargo = 7, yUpperAboveCargo = 22):
    # read in the cargo image
    try:  # see if we are giving it a data array
        filename.shape[0]
        dat = filename
    except:        
        
        if filename[-2:] == 'DR':
            dat = ReadCargoImageDR(filename)
            # invert the image
        else:
            (dat,bpp,formatt,flag,low1,high1,low2,high2) = ReadCargoImage(filename)
    
    # mean intensity of pixels in row of pixels that will be searched for the edge
    collapsed = dat[:,yLower:yUpper].mean(axis = 1)

    # mean intensity of pixels above the cargo; will be used to detect bad pixels
    collapsedAboveCargo = dat[:,yLowerAboveCargo:yUpperAboveCargo].mean(axis = 1)
    
    # threshold used to determine if scan line is bad (no x-rays)
    thresholdAboveCargo =  collapsedAboveCargo[lowerBound:upperBound].mean()/100.;
    
    nearestNeighborValues = np.arange(2)
    width = dat.shape[0]
    # Remove black lines (no x-rays)
    for ii in xrange(lowerBound, upperBound):
        # Find bad scan lines
        if (collapsedAboveCargo[ii] < thresholdAboveCargo):
            print(ii)
            # look left until find good scan line for nearest neighbor value
            for jj in xrange(ii-1,0, -1):
                if (collapsedAboveCargo[jj] > thresholdAboveCargo):
                    nearestNeighborValues[0] = collapsed[jj];
                    break;
            # look right until find good scan line for nearest neighbor value
            for jj in xrange(ii+1, width, 1):
                if (collapsedAboveCargo[jj] > thresholdAboveCargo):
                    nearestNeighborValues[1] = collapsed[jj];
                    break;
            # replace with average of nearest neighbors
            collapsed[ii] = nearestNeighborValues[0]/2 + nearestNeighborValues[1]/2;    
   
    # low value
    low =  collapsed[lowerBound:upperBound].min();
    # get the high value
    high = collapsed[lowerBound:upperBound].max();
    # calculate the threshold
    threshold = (low + high)/2.0;

    # find where the collapsed array crosses the threshold
    startBin = 0;
    for ii in xrange(lowerBound, upperBound):
        if ((collapsed[ii] > threshold) and (collapsed[ii+1] <= threshold)):
            startBin = ii;
            break;
    return(startBin)